-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Fix a crash caused by a bug introduced in C++ overloads support in GetScopeIdOffset()
#6151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…etScopeIdOffset()` After this change, we correctly increment the offset by the next switch case type. Before this change, we accidentally incremented the offset by `functions()` size instead of `cpp_overload_sets()` size and vice versa. Also sorted the switch cases according to the order of the enum, for consistency which might help prevent a future similar incident. This fix prevents crashing in the newly introduced test `multiple_too_few_args_calls`. This also has the side effect of showing `null name` for `cpp_overload_set_type` and `cpp_overload_set_value`, instead of having an arbitrary name. Examples that deomnstrate the old name is arbitrary can easily be seen in tests like `cpp_namespace.carbon` and `decayed_param.carbon`, but careful review would show that all old names are arbitrary, though often luckily almost make sense.
… a simple type Before this change, we wrongly ignore the decision to generate a thunk for a function with default args by overriding this decision with the fact the return type by itself doesn't require a thunk. This causes not generating a thunk which leads to crashing in lowering. Add tests that show that now thunk is generated in `check` and it no longer crashes in `lower. Based on carbon-language#6151. Follow up of carbon-language#6108.
case ScopeIdTypeEnum::For<SpecificInterfaceId>: | ||
offset += sem_ir_->vtables().size(); | ||
[[fallthrough]]; | ||
case ScopeIdTypeEnum::For<VtableId>: | ||
// All type-specific scopes are offset by `FirstEntityScope`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks weird to me. We're using vtables.size for the specific interface? And for Vtable we're using a fixed offset with a comment about specific scopes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it looks weird, and I tried to explain the bug fix in the description, but probably not well enough.
See the comment before the switch, each type's offset excludes its own type.
The bug was introduced in #5891, take a look at the code before the bug was introduced:
carbon-lang/toolchain/sem_ir/inst_namer.cpp
Lines 129 to 155 in 64139e5
switch (id_enum) { | |
case ScopeIdTypeEnum::None: | |
// `None` will be getting a full count of scopes. | |
offset += sem_ir_->associated_constants().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<AssociatedConstantId>: | |
offset += sem_ir_->classes().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<ClassId>: | |
offset += sem_ir_->vtables().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<VtableId>: | |
offset += sem_ir_->functions().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<FunctionId>: | |
offset += sem_ir_->impls().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<ImplId>: | |
offset += sem_ir_->interfaces().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<InterfaceId>: | |
offset += sem_ir_->specific_interfaces().size(); | |
[[fallthrough]]; | |
case ScopeIdTypeEnum::For<SpecificInterfaceId>: | |
// All type-specific scopes are offset by `FirstEntityScope`. | |
offset += static_cast<int>(ScopeId::FirstEntityScope); | |
return offset; |
You can see each type adds the size for next switch case type.
The [[fallthrough]]
and the comment above the switch is the key here I think.
This change fixes the code for that original logic.
Does this make sense or do I miss something in your comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, this causes confusion indeed. Maybe refactoring as a follow-up would be beneficial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it thank you. LGTM
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Refactoring PR: #6159.
// CHECK:STDOUT: import Cpp//... | ||
// CHECK:STDOUT: } | ||
// CHECK:STDOUT: %.0b7: %.6e5 = cpp_overload_set_value @foo [concrete = constants.%empty_struct] | ||
// CHECK:STDOUT: %.0b7: %.6e5 = cpp_overload_set_value @<null name> [concrete = constants.%empty_struct] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We seem to have lost all the names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, tried to explain that in the description.
I believe the original names were somewhat arbitrary because we looked at the wrong index, and that what causes the crash that I've fixed here.
You can see names like CallQualified
or HasQualifiers.plain
before this change, which are clearly wrong.
We can work towards adding proper names, but I think this should not block making this fix so we don't access arbitrary items in the array, which sometimes causes crashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I'm trying to set the names properly in #6156.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found this strange as well, so I'd prefer landing #6156 as it brings more context for this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, I don't mind #6156 merged without having this one merged, though I find the two PRs somewhat separate (one is fixing a bug that causes a crash, which has a side effect of not showing wrong names and the other is properly setting the names).
Since the crash is blocking other efforts, I'd prefer to merge this one in case #6156 requires more discussions.
[[fallthrough]]; | ||
case ScopeIdTypeEnum::For<CppOverloadSetId>: | ||
offset += sem_ir_->cpp_overload_sets().size(); | ||
offset += sem_ir_->functions().size(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also looks off to me, indices after (things listed before in the switch) the CppOverloadSetIds aren't being offset by the size of cpp overload sets?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's correct, see my reply to your other comment.
This is a followup of carbon-language#5891. Based on carbon-language#6151. Part of carbon-language#5915.
This is a followup of carbon-language#5891. Based on carbon-language#6151. Part of carbon-language#5915.
case ScopeIdTypeEnum::For<SpecificInterfaceId>: | ||
offset += sem_ir_->vtables().size(); | ||
[[fallthrough]]; | ||
case ScopeIdTypeEnum::For<VtableId>: | ||
// All type-specific scopes are offset by `FirstEntityScope`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it thank you. LGTM
…end and maintain Instead of having a switch case with `fallthrough` where each case adds the number of entities of the next id type case, have an array that maps id type to a function that gets the number of the matching entities. This array is less confusing and easier to maintain to avoid bugs like the one fixed in carbon-language#6151. The logic that sums only the entities above the given id is now a common logic so no need to change it when changing the set of ids.
…end and maintain Instead of having a switch case with `fallthrough` where each case adds the number of entities of the next id type case, have an array that maps id type to a function that gets the number of the matching entities. This array is less confusing and easier to maintain to avoid bugs like the one fixed in carbon-language#6151. The logic that sums only the entities above the given id is now a common logic so no need to change it when changing the set of ids.
…tNamer::GetScopeIdOffset()` This would hopefully help prevent bugs like the one fixed in carbon-language#6151.
After this change, we correctly increment the offset by the next switch case type.
Before this change, we accidentally incremented the offset by
functions()
size instead ofcpp_overload_sets()
size and vice versa.Also sorted the switch cases according to the order of the enum, for consistency. This might help prevent a future similar incident.
This fix prevents crashing in the newly introduced test
multiple_too_few_args_calls
.This also has the side effect of showing
null name
forcpp_overload_set_type
andcpp_overload_set_value
, instead of having an arbitrary name.Examples that demonstrate the old name is arbitrary can easily be seen in tests like
cpp_namespace.carbon
anddecayed_param.carbon
, but careful review would show that all old names are arbitrary, though often luckily almost make sense.We might want to have a proper name for these, but it's beyond the scope of this crash fixing change.
See #6156.
Part of #5915.